/*
 * Copyright 2015-2016 Tumblr, Inc.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.tumblr.backboard.example;

import com.facebook.rebound.Spring;
import com.facebook.rebound.SpringConfig;
import com.facebook.rebound.SpringListener;
import com.facebook.rebound.SpringSystem;
import com.tumblr.backboard.Utils.View;
import com.tumblr.backboard.performer.Performer;
import ohos.agp.components.AttrHelper;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.DependentLayout;
import ohos.agp.components.element.ShapeElement;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.multimodalinput.event.TouchEvent;

import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.List;

/**
 * Demonstrates creating and removing
 *
 * @author ericleong
 * @since 2021-05-07
 */
public class ExplosionFragment extends BaseFraction {
    private static final int DIAMETER = 80;
    private static final int END_VALUE = 9001;
    private static final int DELAY_TIME = 100;
    private static final int ONE_THOUSAND = 1000;
    private static final int THREE_THOUSAND = 3000;
    private static final int TWO = 2;
    private static final int FOUR = 4;

    private DependentLayout mRootView;

    private int colorIndex;
    private List<Integer> mCircles;

    private EventHandler mHandler;
    private Runnable mRunnable;
    private boolean mIsTouching;

    private SpringSystem mSpringSystem;

    private SpringConfig mCoasting;
    private SpringConfig mGravity;

    /**
     * Destroys the attached Spring.
     *
     * @author ericleong
     * @since 2021-05-07
     */
    private static class Destroyer implements SpringListener {
        private int mMin;
        private int mMax;
        private ComponentContainer mViewGroup;
        private Component mViewToRemove;

        private Destroyer(ComponentContainer viewGroup, Component viewToRemove, int min, int max) {
            mViewGroup = viewGroup;
            mViewToRemove = viewToRemove;
            mMin = min;
            mMax = max;
        }

        private boolean shouldClean(Spring spring) {
            // these are arbitrary values to keep the view from disappearing before it is
            // fully off the screen
            return spring.getCurrentValue() < mMin || spring.getCurrentValue() > mMax;
        }

        private void clean(Spring spring) {
            if (mViewGroup != null && mViewToRemove != null) {
                mViewGroup.removeComponent(mViewToRemove);
            }
            if (spring != null) {
                spring.destroy();
            }
        }

        @Override
        public void onSpringUpdate(Spring spring) {
            if (shouldClean(spring)) {
                clean(spring);
            }
        }

        @Override
        public void onSpringAtRest(Spring spring) {
        }

        @Override
        public void onSpringActivate(Spring spring) {
        }

        @Override
        public void onSpringEndStateChange(Spring spring) {
        }
    }

    /**
     * CircleSpawn.
     *
     * @author ericleong
     * @since 2021-05-07
     */
    private class CircleSpawn implements Runnable {
        @Override
        public void run() {
            if (mIsTouching) {
                colorIndex++;
                if (colorIndex >= mCircles.size()) {
                    colorIndex = 0;
                }
                ShapeElement shapeElement = new ShapeElement(getFractionAbility(), mCircles.get(colorIndex));
                createCircle(mRootView, mSpringSystem, mCoasting, mGravity, shapeElement);
                mHandler.postTask(this, DELAY_TIME);
            }
        }
    }

    private void createCircle(ComponentContainer rootView,
                              SpringSystem springSystem,
                              SpringConfig coasting,
                              SpringConfig gravity,
                              ShapeElement backgroundDrawable) {
        final Spring springX = springSystem.createSpring().setSpringConfig(coasting);
        final Spring springY = springSystem.createSpring().setSpringConfig(gravity);

        // create view
        Component view = new Component(getFractionAbility());
        DependentLayout.LayoutConfig params = new DependentLayout.LayoutConfig(AttrHelper.vp2px(DIAMETER,
                getFractionAbility()),
                AttrHelper.vp2px(DIAMETER, getFractionAbility()));
        params.addRule(DependentLayout.LayoutConfig.CENTER_IN_PARENT);
        view.setLayoutConfig(params);
        view.setBackground(backgroundDrawable);
        rootView.addComponent(view);

        // generate random direction and magnitude
        double magnitude = (new SecureRandom().nextDouble()) * ONE_THOUSAND + THREE_THOUSAND;
        double angle = (new SecureRandom().nextDouble()) * Math.PI / TWO + Math.PI / FOUR;

        springX.setVelocity(magnitude * Math.cos(angle));
        springY.setVelocity(-magnitude * Math.sin(angle));

        int maxX = rootView.getWidth() / TWO;
        springX.addListener(new Destroyer(rootView, view, -maxX, maxX));

        int maxY = rootView.getHeight() / TWO;
        springY.addListener(new Destroyer(rootView, view, -maxY, maxY));

        springX.addListener(new Performer(view, View.TRANSLATION_X));
        springY.addListener(new Performer(view, View.TRANSLATION_Y));

        springX.setEndValue(TWO);
        springY.setEndValue(END_VALUE);
    }

    @Override
    public int getUiContent() {
        return ResourceTable.Layout_fragment_bloom;
    }

    @Override
    public void initComponent() {
        mSpringSystem = SpringSystem.create();
        mCoasting = SpringConfig.fromOrigamiTensionAndFriction(0, 0);
        mCoasting.tension = 0;
        mGravity = SpringConfig.fromOrigamiTensionAndFriction(0, 0);
        mGravity.tension = 1;
        mRootView = (DependentLayout) mComponent;
        mCircles = new ArrayList<>();
        mCircles.add(ResourceTable.Graphic_circle_green);
        mCircles.add(ResourceTable.Graphic_circle_red);
        mCircles.add(ResourceTable.Graphic_circle_purple);
        mCircles.add(ResourceTable.Graphic_circle_orange);
        mCircles.add(ResourceTable.Graphic_circle_blue);
        mCircles.add(ResourceTable.Graphic_circle_gray);
        mRunnable = new CircleSpawn();
        EventRunner runner = EventRunner.current();
        mHandler = new EventHandler(runner);
        mRootView.setTouchEventListener(new Component.TouchEventListener() {
            @Override
            public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
                switch (touchEvent.getAction()) {
                    case TouchEvent.PRIMARY_POINT_DOWN:
                        mIsTouching = true;
                        mHandler.postTask(mRunnable);
                        break;
                    case TouchEvent.PRIMARY_POINT_UP:
                        mIsTouching = false;
                        break;
                    default:
                        break;
                }
                return true;
            }
        });
    }
}
